import traceback

_g_google_cache = {}

user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.57'

def google(query, num_results):
    import googlesearch
    content = []
    googlesearch.get_useragent = lambda: user_agent
    for result in googlesearch.search(query, advanced=True, num_results=num_results, sleep_interval=0, timeout=5, lang='zh'):
        content.append(dict(url=result.url, title=result.title, body=result.description))
    return content

def duckduckgo(query, num_results):
    from duckduckgo_search import DDGS
    from itertools import islice
    results = []
    with DDGS() as ddgs:
        ddgs_gen = ddgs.text(query, timelimit='y', backend="lite", region="zh-cn")
        for r in islice(ddgs_gen, num_results):
            results.append(dict(url=r['href'], title=r['title'], body=r['body']))
    return results

def bing(query, num_results):
    import requests
    from bs4 import BeautifulSoup
    from itertools import islice
    url = 'https://cn.bing.com/search?q=' + query
    headers = {
        'User-Agent': user_agent,
    }
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.text, 'html.parser')
    results = []
    for result in islice(soup.find_all('li', class_='b_algo'), num_results):
        title = result.find('h2').text
        link = result.find('a')['href']
        try:
            snippet = result.find('p').text
        except:
            snippet = None
        results.append(dict(url=link, title=title, body=snippet))
    return results

def baidu(query, num_results):
    import requests
    from bs4 import BeautifulSoup
    from itertools import islice
    url = 'https://www.baidu.com/s?wd=' + query
    headers = {
        'User-Agent': user_agent,
    }
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.text, 'html.parser')
    results = []
    for result in islice(soup.find_all('div', class_='result'), num_results):
        title = result.find('h3').text
        link = result.find('a')['href']
        snippet = result.find('div', class_='c-abstract').text
        results.append(dict(url=link, title=title, body=snippet))
    return results

search_engines = [bing, google, duckduckgo]

def google_search(query: str, num_results: int = 5):
    if query in _g_google_cache:
        content = _g_google_cache[query]
    else:
        error = None
        for searcher in search_engines:
            try:
                content = searcher(query, num_results)
                if len(content) > 0:
                    break
            except:
                traceback.print_exc()
                if error is None:
                    error = traceback.format_exc()
        else:
            if error is None:
                return {'error': 'Empty search result, try other keywords instead'}
            else:
                return {'error': 'Failed to search for google due to network error', 'traceback': error}
        _g_google_cache[query] = content
    return content

if __name__ == "__main__":
    content = google_search('hello world')
    print(content)
